Skip to content

fix: allow same-name staged attachments#1950

Open
Ap4sh wants to merge 1 commit into
session-foundation:devfrom
Ap4sh:fix-staged-attachments-same-name
Open

fix: allow same-name staged attachments#1950
Ap4sh wants to merge 1 commit into
session-foundation:devfrom
Ap4sh:fix-staged-attachments-same-name

Conversation

@Ap4sh

@Ap4sh Ap4sh commented Jun 2, 2026

Copy link
Copy Markdown

First time contributor checklist:

Contributor checklist:

  • My commit is in a nice logical chunk with a good commit message
  • My changes are rebased on the latest dev branch
  • Build, lint, and tests pass locally
  • My changes are ready to be shipped to users

Description

Fixes #241

This fixes staged attachment handling when multiple selected files have the same filename

Previously staged attachments were deduped and removed by fileName, so adding two files named image.jpg only kept one item. Removing by filename also could not target one specific same-name attachment

This PR adds a local stagedAttachmentId for staged attachments and uses that id for rendering, dedupe, and single-item removal. The id stays local to staged attachments and is not included in outgoing attachment payloads

Testing

  • Added reducer coverage for keeping same-name attachments with different staged ids
  • Added reducer coverage for removing only one same-name staged attachment and revoking only its object URLs
  • Added reducer coverage for the voice-message staging guard in both directions
  • corepack pnpm dedupe --check
  • Full build pipeline: clean, local config, protobuf, source copy, tsc, Babel compile, Sass, SVG, and workers
  • corepack pnpm exec prettier --check "*.{css,js,json,scss,ts,tsx}" "./**/*.{css,js,json,scss,ts,tsx}"
  • corepack pnpm exec eslint --cache .
  • Full Mocha suite, 912 passing

@Ap4sh Ap4sh changed the title fix staged attachment removal for duplicate filenames fix: allow same-name staged attachments Jun 2, 2026
@Ap4sh Ap4sh marked this pull request as ready for review June 2, 2026 21:14
Copilot AI review requested due to automatic review settings June 2, 2026 21:14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR migrates staged-attachment identity and removal semantics from fileName-based to a stable stagedAttachmentId, preventing collisions when multiple attachments share the same filename.

Changes:

  • Add stagedAttachmentId to StagedAttachmentType and generate ids when staging files/previews.
  • Update staged-attachments reducer to de-dupe and remove by stagedAttachmentId instead of fileName, and tighten voice-message staging rules.
  • Add unit tests covering de-dupe/removal behavior and voice-message constraints.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ts/util/attachment/attachmentsUtil.ts Updates imported staged-attachment type definition to omit stagedAttachmentId.
ts/state/ducks/stagedAttachments.ts Switches uniq/removal logic to use stagedAttachmentId and refines voice-message gating.
ts/components/conversation/composition/CompositionBox.tsx Changes audio voice-note staged attachment shape/type.
ts/components/conversation/StagedAttachmentList.tsx Removes staged attachments by stagedAttachmentId and uses it as a React key fallback.
ts/components/conversation/SessionConversation.tsx Assigns stagedAttachmentId when creating staged attachments and previews.
ts/test/session/unit/staged_attachments/StagedAttachments_test.ts Adds unit tests for id-based staging/removal and voice-message constraints.
Comments suppressed due to low confidence (1)

ts/util/attachment/attachmentsUtil.ts:1

  • The reducer and UI now treat stagedAttachmentId as the primary identity (de-dupe, removal, React keys). Omitting stagedAttachmentId from StagedAttachmentImportedType makes it easy to construct “staged-like” objects without ids (as seen in CompositionBox), which breaks those invariants. Prefer keeping stagedAttachmentId on imported staged attachments, or enforce a single conversion step that always generates/assigns stagedAttachmentId before such objects can reach the staged-attachments state/UI.
/* eslint-disable max-len */

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +811 to 819
const audioAttachment: StagedAttachmentImportedType = {
contentType: MIME.AUDIO_MP3,
size: savedAudioFile.size,
fileSize: null,
screenshot: null,
fileName: 'session-audio-message',
thumbnail: null,
url: '',
isVoiceMessage: true,
path: savedAudioFile.path,
};

@Ap4sh Ap4sh Jun 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path does not go through staged attachment state

sendVoiceMessage builds a StagedAttachmentImportedType and sends it directly through sendMessage, while stagedAttachmentId is only required on StagedAttachmentType before getFileAndStoreLocally

Keeping it omitted from StagedAttachmentImportedType is intentional so the local staging id does not leak into outgoing attachment payloads

Comment on lines +38 to 45
if (
(hasNewVoiceMessage &&
(currentStagedAttachments.length > 0 || newAttachments.length > 1)) ||
(hasCurrentVoiceMessage && newAttachments.length > 0)
) {
window?.log?.warn('A voice note cannot be sent with other attachments');
return state;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Allow to stage multiple attachments with the same name.

2 participants